<?php
/**
 * Copyright (c) 2012, xxworkshop Inc.
 * All rights reserved.
 *
 * Created by BrocheXu on 2014.11.6
 */
 
require_once 'config/replytype.config.inc.php';
require_once 'basedistributor.class.php';
require_once 'responsehandler/textresponsehandler.class.php';

class WXHandler {
	private $appid;
	private $aeskey;
	private $token;
	private $postObject;
	
	private $distributor;

	public function __construct($appid, $aeskey, $token) {
		if (empty($appid)) {
			throw new Exception('appid is required');
		}
		if (empty($aeskey)) {
			throw new Exception('aeskey is required');
		}
		if (empty($token)) {
			throw new Exception('token is required');
		}
		
// 		if (method_exists($this, 'errorHandler'))
// 			set_error_handler(array($this, 'errorHandler'));
// 		
// 		if (method_exists($this, 'exceptionHandler'))
// 			set_exception_handler(array($this, 'exceptionHandler'));
		
		$this->appid = $appid;
		$this->aeskey = $aeskey;
		$this->token = $token;
		
		$this->postObject = $this->parsePostRequestData();
	}
	
	private function parsePostRequestData() {
		if ($this->checkSignature()) {
			if (!empty($_GET['echostr'])) {
				echo $_GET['echostr'];
				exit;
			} else {
				if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
					$rawData = $GLOBALS['HTTP_RAW_POST_DATA'];
					$data = simplexml_load_string($rawData, 'SimpleXMLElement', LIBXML_NOCDATA);
					if ($data === false) {
						throw new Exception('parse raw data error');
					} else {
						return $data;
					}
				} else {
					throw new Exception('request method is not post');
				}
			}
		} else {
			throw new Exception('signature check failed');
		}
	}
	
	private function checkSignature() {
		$signature = $_GET['signature'];
		$timestamp = $_GET['timestamp'];
		$nonce = $_GET['nonce'];
	
		$params = array($this->token, $timestamp, $nonce);
		sort($params, SORT_STRING);
		$sig = sha1(implode($params));
	
		return $sig == $signature;
	}
	
	public function run() {
		if (empty($this->distributor)) {
			throw new Exception('distributor is empty');
		}
		
		$responseHandler = $this->distributor->process($this->postObject);
		if (empty($responseHandler)) {
			$responseHandler = new DefaultResponseHandler($this->postObject);
		}
		$replytype = $responseHandler->getReplyType();
		$text = '';
		if ($replytype == REPLY_TYPE_TEXT) {
			$text = $this->generateText($responseHandler);
		} else if ($replytype == REPLY_TYPE_IMAGE) {
			$text = $this->generateImage($responseHandler);
		} else if ($replytype == REPLY_TYPE_VOICE) {
			$text = $this->generateVoice($responseHandler);
		} else if ($replytype == REPLY_TYPE_VIDEO) {
			$text = $this->generateVideo($responseHandler);
		} else if ($replytype == REPLY_TYPE_MUSIC) {
			$text = $this->generateMusic($responseHandler);
		} else if ($replytype == REPLY_TYPE_NEWS) {
			$text = $this->generateNews($responseHandler);
		} else if ($replytype == REPLY_TYPE_EMPTY) {
			$text = '';
		}
		echo $text;
	}
	
	public function setDistributor($distributor) {
		$this->distributor = $distributor;
		return $this;
	}
	
	private function generateText($responseHandler) {
		if (empty($responseHandler)) {
			throw new Exception('text is empty');
		}
		$content = $responseHandler->build();
		$textTpl = '<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%s</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType>
				<Content><![CDATA[%s]]></Content>
			</xml>';
		$text = sprintf($textTpl, $this->postObject->FromUserName, $this->postObject->ToUserName, time(), REPLY_TYPE_TEXT, $content);
		return $text;
	}
	
	private function generateImage($responseHandler) {
		if (empty($responseHandler)) {
			throw new Exception('image is empty');
		}
		$content = $responseHandler->build();
		$textTpl = '<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%s</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType>
				<Image>%s</Image>
			</xml>';
		$imageTpl = '<MediaId><![CDATA[%s]]></MediaId>';
		
		$image = sprintf($imageTpl, $content);
		$text = sprintf($textTpl, $this->postObject->FromUserName, $this->postObject->ToUserName, time(), REPLY_TYPE_IMAGE, $image);
		return $text;
	}
	
	private function generateVoice($responseHandler) {
		if (empty($responseHandler)) {
			throw new Exception('voice is empty');
		}
		$content = $responseHandler->build();
		$textTpl = '<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%s</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType>
				<Voice>%s</Voice>
			</xml>';
		$voiceTpl = '<MediaId><![CDATA[%s]]></MediaId>';
		
		$voice = sprintf($voiceTpl, $content);
		$text = sprintf($textTpl, $this->postObject->FromUserName, $this->postObject->ToUserName, time(), REPLY_TYPE_VOICE, $voice);
		return $text;
	}
	
	private function generateVideo($responseHandler) {
		if (empty($responseHandler)) {
			throw new Exception('video is empty');
		}
		$content = $responseHandler->build();
		$textTpl = '<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%s</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType>
				<Video>%s</Video>
			</xml>';
		$videoTpl = '<MediaId><![CDATA[%s]]></MediaId>
					<Title><![CDATA[%s]]></Title>
					<Description><![CDATA[%s]]></Description>';
		
		$video = sprintf($videoTpl, $content['mediaid'], $content['title'], $content['description']);
		$text = sprintf($textTpl, $this->postObject->FromUserName, $this->postObject->ToUserName, time(), REPLY_TYPE_VIDEO, $video);
		return $text;
	}
	
	private function generateMusic($responseHandler){
		if (empty($responseHandler)) {
			throw new Exception('music is empty');
		}
		$content = $responseHandler->build();
		$textTpl = '<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%s</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType> 
				<Music>%s</Music>
			</xml>';
		$musicTpl = '<Title><![CDATA[%s]]></Title>
			<Description><![CDATA[%s]]></Description>
			<MusicUrl><![CDATA[%s]]></MusicUrl>
			<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
			<ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>';
		$music = sprintf($musicTpl, $content['title'], $content['description'], $content['musicurl'], $content['hqmusicurl'], $content['thumbmediaid']);
		$text = sprintf($textTpl, $this->postObject->FromUserName, $this->postObject->ToUserName, time(), REPLY_TYPE_MUSIC, $music);
		return $text;
	}
	
	private function generateNews($responseHandler) {
		if (empty($responseHandler)) {
			throw new Exception('news is empty');
		}
		$content = $responseHandler->build();
		$textTpl = '<xml>
				<ToUserName><![CDATA[%s]]></ToUserName>
				<FromUserName><![CDATA[%s]]></FromUserName>
				<CreateTime>%s</CreateTime>
				<MsgType><![CDATA[%s]]></MsgType>
				<ArticleCount>%d</ArticleCount>
				<Articles>%s</Articles>
			</xml>';
		$itemTpl = '<item>
				<Title><![CDATA[%s]]></Title>
				<Discription><![CDATA[%s]]></Discription>
				<PicUrl><![CDATA[%s]]></PicUrl>
				<Url><![CDATA[%s]]></Url>
			</item>';
		$items = '';
		foreach ($content as $item) {
			$items .= sprintf($itemTpl, $item['title'], $item['description'], $item['picurl'], $item['url']);
		}
		$text = sprintf($textTpl, $this->postObject->FromUserName, $this->postObject->ToUserName, time(), REPLY_TYPE_NEWS, count($content), $items);
		return $text;
	}
}

class DefaultResponseHandler extends TextResponseHandler {
	public function process($postObject) {
		return '您输入的内容目前尚未支持';
	}
}
?>